// =========================================
// ALSA 录音工具实现文件
// 功能：实现设备管理、参数设置、录音和 WAV 文件写入
// 作者：你的名字
// 日期：2025-09-17
// =========================================

#include "bsp_alsa.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <unistd.h>

// -----------------------------
// AlsaDevice 类方法实现
// -----------------------------
AlsaDevice::AlsaDevice(snd_pcm_t *handle) : handle_(handle) {}
AlsaDevice::~AlsaDevice()
{
    if (handle_)
        snd_pcm_close(handle_);
}
AlsaDevice::AlsaDevice(AlsaDevice &&other) noexcept : handle_(other.handle_) { other.handle_ = nullptr; }
AlsaDevice &AlsaDevice::operator=(AlsaDevice &&other) noexcept
{
    if (this != &other)
    {
        if (handle_)
            snd_pcm_close(handle_);
        handle_ = other.handle_;
        other.handle_ = nullptr;
    }
    return *this;
}
snd_pcm_t *AlsaDevice::get() const { return handle_; }
AlsaDevice::operator snd_pcm_t *() const { return handle_; }

// -----------------------------
// 格式字符串到 ALSA 枚举的映射表定义
// -----------------------------
const std::map<std::string, snd_pcm_format_t> AlsaRecorder::format_map_ = {
    {"S8", SND_PCM_FORMAT_S8},
    {"U8", SND_PCM_FORMAT_U8},
    {"S16_LE", SND_PCM_FORMAT_S16_LE},
    {"S16_BE", SND_PCM_FORMAT_S16_BE},
    {"U16_LE", SND_PCM_FORMAT_U16_LE},
    {"U16_BE", SND_PCM_FORMAT_U16_BE},
    {"S24_LE", SND_PCM_FORMAT_S24_LE},
    {"S24_BE", SND_PCM_FORMAT_S24_BE},
    {"U24_LE", SND_PCM_FORMAT_U24_LE},
    {"U24_BE", SND_PCM_FORMAT_U24_BE},
    {"S32_LE", SND_PCM_FORMAT_S32_LE},
    {"S32_BE", SND_PCM_FORMAT_S32_BE},
    {"U32_LE", SND_PCM_FORMAT_U32_LE},
    {"U32_BE", SND_PCM_FORMAT_U32_BE},
    {"FLOAT_LE", SND_PCM_FORMAT_FLOAT_LE},
    {"FLOAT_BE", SND_PCM_FORMAT_FLOAT_BE},
    {"FLOAT64_LE", SND_PCM_FORMAT_FLOAT64_LE},
    {"FLOAT64_BE", SND_PCM_FORMAT_FLOAT64_BE}};

// -----------------------------
// AlsaRecorder 类方法实现
// -----------------------------
AlsaRecorder::AlsaRecorder()
    : device_(DEFAULT_DEVICE), sample_rate_(DEFAULT_SAMPLE_RATE),
      channels_(DEFAULT_CHANNELS), format_(DEFAULT_FORMAT),
      duration_(DEFAULT_DURATION), filename_(DEFAULT_FILENAME) {}

AlsaRecorder::AlsaRecorder(const std::string &device, unsigned int sample_rate, int channels,
                           snd_pcm_format_t format, int duration, const std::string &filename)
    : device_(device), sample_rate_(sample_rate), channels_(channels),
      format_(format), duration_(duration), filename_(filename) {}

/**
 * @brief 获取指定 ALSA 格式的物理位宽
 * @param format ALSA 格式枚举
 * @return 位宽（如16、24、32）
 */
int AlsaRecorder::get_bits_per_sample(snd_pcm_format_t format)
{
    return snd_pcm_format_physical_width(format);
}

/**
 * @brief 将格式字符串解析为 ALSA 枚举
 * @param format_str 格式字符串（如 "S16_LE"）
 * @return ALSA 格式枚举
 */
snd_pcm_format_t AlsaRecorder::parse_format(const std::string &format_str)
{
    auto it = format_map_.find(format_str);
    if (it != format_map_.end())
        return it->second;
    std::cerr << "Unknown format: " << format_str << ", using default S16_LE\n";
    return DEFAULT_FORMAT;
}

/**
 * @brief 写入标准 WAV 文件头
 * @param file 输出流
 * @param sample_rate 采样率
 * @param channels 声道数
 * @param bits_per_sample 位深度
 * @param data_size 音频数据字节数
 * @return 写入成功返回 true
 */
bool AlsaRecorder::write_wav_header(std::ofstream &file, uint32_t sample_rate, uint16_t channels,
                                    uint16_t bits_per_sample, uint32_t data_size)
{
    WavHeader header = {};
    uint32_t byte_rate = sample_rate * channels * bits_per_sample / 8;
    uint16_t block_align = channels * bits_per_sample / 8;
    std::memcpy(header.riff, "RIFF", 4);
    header.file_size = 36 + data_size;
    std::memcpy(header.wave, "WAVE", 4);
    std::memcpy(header.fmt, "fmt ", 4);
    header.fmt_chunk_size = 16;
    header.audio_format = 1;
    header.num_channels = channels;
    header.sample_rate = sample_rate;
    header.byte_rate = byte_rate;
    header.block_align = block_align;
    header.bits_per_sample = bits_per_sample;
    std::memcpy(header.data, "data", 4);
    header.data_chunk_size = data_size;
    file.write(reinterpret_cast<const char *>(&header), sizeof(WavHeader));
    return file.good();
}

/**
 * @brief 设置 ALSA 设备硬件参数
 * @param handle ALSA 设备句柄
 * @return 设置成功返回 true
 */
bool AlsaRecorder::set_alsa_parameters(snd_pcm_t *handle) const
{
    snd_pcm_hw_params_t *hw_params;
    snd_pcm_hw_params_alloca(&hw_params);
    int err = snd_pcm_hw_params_any(handle, hw_params);
    if (err < 0)
    {
        std::cerr << "Cannot initialize hardware parameter structure (" << snd_strerror(err) << ")\n";
        return false;
    }
    err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0)
    {
        std::cerr << "Cannot set access type (" << snd_strerror(err) << ")\n";
        return false;
    }
    err = snd_pcm_hw_params_set_format(handle, hw_params, format_);
    if (err < 0)
    {
        std::cerr << "Cannot set sample format (" << snd_strerror(err) << ")\n";
        return false;
    }
    err = snd_pcm_hw_params_set_rate_near(handle, hw_params, const_cast<unsigned int *>(&sample_rate_), nullptr);
    if (err < 0)
    {
        std::cerr << "Cannot set sample rate (" << snd_strerror(err) << ")\n";
        return false;
    }
    err = snd_pcm_hw_params_set_channels(handle, hw_params, channels_);
    if (err < 0)
    {
        std::cerr << "Cannot set channel count (" << snd_strerror(err) << ")\n";
        return false;
    }
    err = snd_pcm_hw_params(handle, hw_params);
    if (err < 0)
    {
        std::cerr << "Cannot set parameters (" << snd_strerror(err) << ")\n";
        return false;
    }
    return true;
}

/**
 * @brief 执行录音流程
 * @return 录音成功返回 true
 */
bool AlsaRecorder::record(std::vector<uint8_t> &buffer)
{
    snd_pcm_t *raw_handle = nullptr;
    int err = snd_pcm_open(&raw_handle, device_.c_str(), SND_PCM_STREAM_CAPTURE, 0);
    if (err < 0)
    {
        std::cerr << "Cannot open audio device " << device_ << " (" << snd_strerror(err) << ")\n";
        return false;
    }
    AlsaDevice capture_handle(raw_handle);
    if (!set_alsa_parameters(capture_handle.get()))
        return false;
    err = snd_pcm_prepare(capture_handle.get());
    if (err < 0)
    {
        std::cerr << "Cannot prepare audio interface for use (" << snd_strerror(err) << ")\n";
        return false;
    }
    snd_pcm_uframes_t frames = sample_rate_ * duration_;
    size_t bits_per_sample = get_bits_per_sample(format_);
    size_t bytes_per_frame = channels_ * (bits_per_sample / 8);
    size_t buffer_size = frames * bytes_per_frame;

    buffer.clear();
    buffer.resize(buffer_size);

    // std::cout << "Recording for " << duration_ << " seconds...\n";

    snd_pcm_sframes_t frames_read = snd_pcm_readi(capture_handle.get(), buffer.data(), frames);
    if (frames_read < 0)
    {
        frames_read = snd_pcm_recover(capture_handle.get(), frames_read, 0);
        if (frames_read < 0)
        {
            std::cerr << "snd_pcm_readi failed: " << snd_strerror(frames_read) << "\n";
            return false;
        }
    }
    if (frames_read != static_cast<snd_pcm_sframes_t>(frames))
    {
        std::cerr << "Short read, read " << frames_read << " frames (expected " << frames << ")\n";
    }
    // else
    // {
    //     std::cout << "Recording finished.\n";
    // }
    // std::ofstream fout(filename_, std::ios::binary);
    // if (!fout.is_open())
    // {
    //     std::cerr << "Failed to open output file: " << filename_ << "\n";
    //     return false;
    // }
    // write_wav_header(fout, sample_rate_, channels_, bits_per_sample, frames_read * bytes_per_frame);
    // size_t data_bytes_to_write = frames_read * bytes_per_frame;
    // fout.write(buffer.data(), data_bytes_to_write);
    // if (!fout.good())
    // {
    //     std::cerr << "Failed to write audio data to file\n";
    //     return false;
    // }
    // std::cout << "Audio data written to " << filename_ << "\n";
    return true;
}

